package com.uwlaser.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.uwlaser.domain.*;
import com.uwlaser.service.FactoryPlanHaltProductionService;
import com.uwlaser.service.FactoryShiftService;
import com.uwlaser.service.OeeService;
import com.uwlaser.service.dto.EquipmentOeeDao;
import com.uwlaser.service.dto.FactoryPlanHaltProductionDto;
import com.uwlaser.service.dto.FactoryShiftDto;
import com.uwlaser.service.dto.ProductionLineOeeDao;
import com.uwlaser.service.mapper.*;
import lombok.AllArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author mx
 * @ClassName:
 * @description:
 * @create 2022-11-11 9:31
 */
@Service
@AllArgsConstructor
// @CacheConfig(cacheNames = SpcAbnormalRuleService.CACHE_KEY)
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class)
public class OeeServiceImpl implements OeeService {

    private final FactoryShiftService factoryShiftService;

    private final CraftOperationMapper craftOperationMapper;

    private final DataPassStationMapper dataPassStationMapper;

    private final FactoryPlanHaltProductionService factoryPlanHaltProductionService;

    private final DeviceAlarmMapper deviceAlarmMapper;

    private final DeviceMainMapper deviceMainMapper;

    private final DataMainMapper dataMainMapper;

    private final DeviceStatusMapper deviceStatusMapper;

    @Override
    public ResponseEntity getEquipmentOee(String lienCode) throws ParseException {
        if (!StringUtils.hasText(lienCode)) {
            throw new RuntimeException("当前没有产线信息,请前往配置!");
        }
        //返回数据
        Map<String, Object> map = new HashMap<>();
        //设备oee数据
        List<EquipmentOeeDao> equipmentOeeDaos = new ArrayList<>();
        //整线oee数据
        ProductionLineOeeDao productionLineOeeDao = new ProductionLineOeeDao();
        //获取班次信息
        FactoryShiftDto factoryShiftDto = new FactoryShiftDto();
        factoryShiftDto.setTemplateCode(lienCode);
        FactoryShiftDto classes = factoryShiftService.getClasses(factoryShiftDto);
        //组装班次时间
        assembleClasses(classes);
        //获取工序的进出站信息
        List<DataPassStation> dataPassStations = dataPassStationMapper.selectList(new LambdaQueryWrapper<DataPassStation>()
                .select(DataPassStation::getResult, DataPassStation::getOperationCode, DataPassStation::getEntryTime, DataPassStation::getExitTime, DataPassStation::getDeviceCode)
                .ge(DataPassStation::getCreateTime, classes.getStartTime()).le(DataPassStation::getCreateTime, classes.getEndTime())
                .isNotNull(DataPassStation::getExitTime));
        //获取计划停机信息
        FactoryPlanHaltProductionDto factoryPlanHaltProductionDto = new FactoryPlanHaltProductionDto();
        factoryPlanHaltProductionDto.setTemplateCode(lienCode);
        List<FactoryPlanHaltProductionDto> plannedStops = factoryPlanHaltProductionService.getPlannedStop(factoryPlanHaltProductionDto);
        List<DeviceAlarm> plannedStop1 = getPlannedStop(plannedStops, classes);
        List<DeviceAlarm> planHalt = new ArrayList<>();
        //计划停机去重
        getHalt(plannedStop1, planHalt, classes.getStartTime(), classes.getEndTime());
        //获取设备信息
        List<DeviceMain> deviceMains = deviceMainMapper.selectList(new LambdaQueryWrapper<DeviceMain>().eq(DeviceMain::getIsOee, "1")
                .eq(DeviceMain::getLineCode, lienCode));
        //获取报警信息
        //获取当前时间段停机信息
        List<DeviceAlarm> deviceAlarms = deviceAlarmMapper.selectList(new LambdaQueryWrapper<DeviceAlarm>()
                .ge(DeviceAlarm::getStartTime, classes.getStartTime()).le(DeviceAlarm::getEndTime, classes.getEndTime()));
        //获取停机还没开机
        List<DeviceAlarm> deviceAlarms1 = deviceAlarmMapper.selectList(new LambdaQueryWrapper<DeviceAlarm>()
                .lt(DeviceAlarm::getStartTime, classes.getStartTime()).isNull(DeviceAlarm::getEndTime));
        //获取停机时间比开始时间早,但在这个时间段运行的停机信息
        List<DeviceAlarm> deviceAlarms2 = deviceAlarmMapper.selectList(new LambdaQueryWrapper<DeviceAlarm>().lt(DeviceAlarm::getStartTime, classes.getStartTime())
                .gt(DeviceAlarm::getEndTime, classes.getStartTime()).le(DeviceAlarm::getEndTime, classes.getEndTime()));
        //获取停机时间大于这个时间段,运行时间也大于这个时间段的停机数据
        List<DeviceAlarm> deviceAlarms3 = deviceAlarmMapper.selectList(new LambdaQueryWrapper<DeviceAlarm>().le(DeviceAlarm::getStartTime, classes.getStartTime())
                .gt(DeviceAlarm::getEndTime, classes.getEndTime()));
        //获取设备状态
        List<DeviceStatus> newestStatus = deviceStatusMapper.getNewestStatus();
        //计算设备oee数据
        for (DeviceMain deviceMain : deviceMains) {
            calculateEquipmentOee(equipmentOeeDaos, deviceAlarms, deviceAlarms1, deviceAlarms2, deviceAlarms3, planHalt, classes, deviceMain, dataPassStations, newestStatus);
        }
        //获取整线oee
        calculateProductionLineOee(productionLineOeeDao, deviceAlarms, deviceAlarms1, deviceAlarms2, deviceAlarms3, planHalt, classes, lienCode);
        map.put("equipmentOeeDaos", equipmentOeeDaos);
        map.put("productionLineOeeDao", productionLineOeeDao);
        return new ResponseEntity(map, HttpStatus.OK);
    }

    @Override
    public ResponseEntity getWaterlineOee() {
        return null;
    }


    /**
     * 获取设备oee数据
     *
     * @param equipmentOeeDaos     设备oee数据
     * @param equipmentMessageList 时间段的报警信息
     * @param noStartingUp         停机还没开机的报警信息
     * @param timeQuantum          获取停机时间比开始时间早,但在这个时间段运行的停机信息
     * @param fullStop             获取停机时间大于这个时间段,运行时间也大于这个时间段的停机数据
     * @param plannedStop1         计划停机
     * @param classes              班次信息
     * @param deviceMain           设备信息
     * @param dataPassStations     生产数据
     */
    public void calculateEquipmentOee(List<EquipmentOeeDao> equipmentOeeDaos, List<DeviceAlarm> equipmentMessageList, List<DeviceAlarm> noStartingUp, List<DeviceAlarm> timeQuantum
            , List<DeviceAlarm> fullStop, List<DeviceAlarm> plannedStop1, FactoryShiftDto classes
            , DeviceMain deviceMain, List<DataPassStation> dataPassStations, List<DeviceStatus> newestStatus) throws ParseException {
        DecimalFormat df = new DecimalFormat("######0.00");
        EquipmentOeeDao equipmentOeeDao = new EquipmentOeeDao();
        //设备名称
        String deviceName = deviceMain.getDeviceName();
        //设备编码
        String deviceCode = deviceMain.getDeviceCode();
        //节拍
        double meter = deviceMain.getMeter().doubleValue();
        //计划停机时间，故障停机时间
        double plannedStop = 0.0, downtime = 0.0;
        //计划时间,当前生产数量,良品数量,合格率,时间稼动率,性能稼动率,oee
        double planTime = 0.0, productTotal = 0.0, oKTotal = 0.0, oKRate = 0.0, timeCropRate = 0.0, perfCropRate = 0.0, oee = 0.0;
        //总停机信息
        List<DeviceAlarm> haltAll = new ArrayList<>();
        //过滤报警信息
        List<DeviceAlarm> deviceAlarms = equipmentMessageList.stream().filter(f -> deviceCode.equals(f.getDeviceCode())).collect(Collectors.toList());
        List<DeviceAlarm> deviceAlarms1 = noStartingUp.stream().filter(f -> deviceCode.equals(f.getDeviceCode())).collect(Collectors.toList());
        List<DeviceAlarm> deviceAlarms2 = timeQuantum.stream().filter(f -> deviceCode.equals(f.getDeviceCode())).collect(Collectors.toList());
        List<DeviceAlarm> deviceAlarms3 = fullStop.stream().filter(f -> deviceCode.equals(f.getDeviceCode())).collect(Collectors.toList());
        //组装停机信息
        getOutageInformation(haltAll, deviceAlarms, deviceAlarms1, deviceAlarms2, deviceAlarms3, classes);
        //过滤停机信息
        getOutageInformation(haltAll, plannedStop1);
        //计划停机时长
        if (!CollectionUtils.isEmpty(plannedStop1)) {
            plannedStop = plannedStop1.stream().map(DeviceAlarm::getTripTime).reduce(BigDecimal.ZERO, BigDecimal::add).doubleValue() / 60;
        }
        //故障停机时长
        if (!CollectionUtils.isEmpty(haltAll)) {
            downtime = haltAll.stream().map(DeviceAlarm::getTripTime).reduce(BigDecimal.ZERO, BigDecimal::add).doubleValue() / 60;
        }
        //获取设备生产数据
        List<DataPassStation> collect1 = dataPassStations.stream().filter(f -> deviceCode.equals(f.getDeviceCode())).collect(Collectors.toList());//
        //计划时间
        planTime = minuteDiff(classes.getStartTime(), classes.getEndTime()) / 60;
        //计划运行时间
        planTime = planTime - plannedStop;
        //运行时间
        double deviceRunTime = (planTime - downtime) < 0 ? 0 : (planTime - downtime);
        //设备稼动时间
        double cropTime = deviceRunTime;
        //计算oee
        if (!CollectionUtils.isEmpty(collect1)) {
            //按状态分组
            Map<String, List<DataPassStation>> collect2 = collect1.stream().collect(Collectors.groupingBy(f -> f.getResult()));
            //当前生产数量
            productTotal = collect1.size();
            //良品数量
            oKTotal = collect2.get("0") == null ? 0 : collect2.get("0").size();
            //合格率
            oKRate = oKTotal == 0 ? 0 : (oKTotal / productTotal);
            //时间稼动率(可稼动时间/计划时间*100)
            timeCropRate = cropTime <= 0 ? 0 : (cropTime / planTime);
            //性能稼动率
            perfCropRate = oKTotal == 0 ? 0 : (cropTime <= 0 ? 0 : meter == 0 ? 0 : (meter * oKTotal / (cropTime * 60 * 60)));
            //oee
            oee = oKRate * timeCropRate * perfCropRate;
        } else {
            //时间稼动率
            timeCropRate = cropTime <= 0 ? 0 : (cropTime / planTime);
        }
        //拼装设备oee数据
        equipmentOeeDao.setDeviceCode(deviceCode);
        equipmentOeeDao.setDeviceName(deviceName);
        equipmentOeeDao.setOkNumber(df.format(oKTotal));
        equipmentOeeDao.setNgNumber(df.format(productTotal - oKTotal));
        equipmentOeeDao.setYield(df.format(oKRate * 100));
        equipmentOeeDao.setTimeEfficency(df.format(timeCropRate * 100));
        equipmentOeeDao.setPerformanceEfficency(df.format(perfCropRate * 100));
        equipmentOeeDao.setOee(df.format(oee * 100));
        //设置设备状态
        if (CollectionUtils.isEmpty(newestStatus)) {
            equipmentOeeDao.setState("6");
        } else {
            //获取当前设备状态
            List<DeviceStatus> collect = newestStatus.stream().filter(f -> deviceCode.equals(f.getDeviceCode())).collect(Collectors.toList());
            equipmentOeeDao.setState(CollectionUtils.isEmpty(collect) ? "6" : collect.get(0).getDeviceStatus());
        }
        equipmentOeeDaos.add(equipmentOeeDao);
    }

    /**
     * 获取产线oee
     */
    /**
     * 获取产线oee
     *
     * @param productionLineOeeDao
     * @param equipmentMessageList
     * @param noStartingUp
     * @param timeQuantum
     * @param fullStop
     * @param plannedStop1
     * @param classes
     */
    public void calculateProductionLineOee(ProductionLineOeeDao productionLineOeeDao, List<DeviceAlarm> equipmentMessageList, List<DeviceAlarm> noStartingUp, List<DeviceAlarm> timeQuantum
            , List<DeviceAlarm> fullStop, List<DeviceAlarm> plannedStop1, FactoryShiftDto classes, String lienCode) throws ParseException {
        DecimalFormat df = new DecimalFormat("######0.00");
        //初始化数据
        //计划时间,停机时间,稼动时间,目标产量,节拍
        double planTime = 0.0, devStopTime = 0.0, deviceRunTime = 0.0, planTotal = 0.0, meter = 0.0;
        //时间稼动率,性能稼动率,oee,当前进度,uph,生产数量,良品数量,合格率,每小时达标率
        double timeCropRate = 0.0, perfCropRate = 0.0, oee = 0.0, controlRates = 0.0, uph = 0.0, productTotal = 0.0, oKTotal = 0.0, oKRate = 0.0, controlRatesHour = 0.0;
        //计划停机时间
        double plannedStop = 0.0;
        //总停机信息
        List<DeviceAlarm> haltAll = new ArrayList<>();
        //组装停机信息
        getOutageInformation(haltAll, equipmentMessageList, noStartingUp, timeQuantum, fullStop, classes);
        //过滤停机信息
        getOutageInformation(haltAll, plannedStop1);
        //计划停机时长
        if (!CollectionUtils.isEmpty(plannedStop1)) {
            plannedStop = plannedStop1.stream().map(DeviceAlarm::getTripTime).reduce(BigDecimal.ZERO, BigDecimal::add).doubleValue() / 60;
        }
        //故障停机时长
        if (!CollectionUtils.isEmpty(haltAll)) {
            devStopTime = haltAll.stream().map(DeviceAlarm::getTripTime).reduce(BigDecimal.ZERO, BigDecimal::add).doubleValue() / 60;
        }
        //获取各个段的生产数据
        List<DataMain> dataMains = dataMainMapper.selectList(new LambdaQueryWrapper<DataMain>().ge(DataMain::getCreateTime, classes.getStartTime())
                .le(DataMain::getCreateTime, classes.getEndTime()).in(DataMain::getResult, "0", "1").eq(DataMain::getProductType, "P")
                .eq(DataMain::getLienCode, lienCode).select(DataMain::getResult));
        //计划时间
        planTime = minuteDiff(classes.getStartTime(), classes.getEndTime()) / 60;
        //计划运行时间
        planTime = planTime - plannedStop;
        //稼动时间
        deviceRunTime = (planTime - devStopTime) < 0 ? 0 : (planTime - devStopTime);
        //节拍
        meter = Double.parseDouble(classes.getMeter());
        planTotal = Double.parseDouble(classes.getYield());
        if (!CollectionUtils.isEmpty(dataMains)) {
            //数据分组
            Map<String, List<DataMain>> collect = dataMains.stream().collect(Collectors.groupingBy(f -> f.getResult()));
            //当前产量
            productTotal = dataMains.size();
            //良品数量
            oKTotal = collect.get("0") == null ? 0 : collect.get("0").size();
            //uph
            if (planTime == 0) {
                uph = 0;
            } else {
                uph = oKTotal == 0 ? 0 : oKTotal / planTime;
            }
            //合格率
            oKRate = oKTotal / productTotal;
            //时间稼动率(可稼动时间/计划时间*100)
            timeCropRate = deviceRunTime <= 0 ? 0 : (deviceRunTime / planTime);
            //性能稼动率=节拍*实际产量/稼动时间*100%
            perfCropRate = oKTotal == 0 ? 0 : (deviceRunTime <= 0 ? 0 : (meter * oKTotal / (deviceRunTime * 60 * 60)));
            //0EE
            oee = oKRate * timeCropRate * perfCropRate;
            //达标率
            controlRates = oKTotal / planTotal;

            //每小时达标率
            if (uph == 0) {
                controlRatesHour = 0;
            } else {
                controlRatesHour = uph / (planTotal / 12);
            }
        } else {
            //时间稼动率
            timeCropRate = deviceRunTime <= 0 ? 0 : (deviceRunTime / planTime);
        }
        //拼装产线oee
        productionLineOeeDao.setPlanTime(df.format(planTime * 60 * 60));
        productionLineOeeDao.setDevStopTime(df.format(devStopTime * 60 * 60));
        productionLineOeeDao.setDeviceRunTime(df.format(deviceRunTime * 60 * 60));
        productionLineOeeDao.setPlanTotal(df.format(planTotal));
        productionLineOeeDao.setMeter(df.format(meter));
        productionLineOeeDao.setTimeCropRate(df.format(timeCropRate * 100));
        productionLineOeeDao.setPerfCropRate(df.format(perfCropRate * 100));
        productionLineOeeDao.setOee(df.format(oee * 100));
        productionLineOeeDao.setControlRates(df.format(controlRates * 100));
        productionLineOeeDao.setUph(df.format(uph));
        productionLineOeeDao.setProductTotal(df.format(productTotal));
        productionLineOeeDao.setOKTotal(df.format(oKTotal));
        productionLineOeeDao.setOKRate(df.format(oKRate * 100));
        productionLineOeeDao.setControlRatesHour(df.format(controlRatesHour * 100));
    }

    /**
     * 组装班次时间
     */
    public void assembleClasses(FactoryShiftDto classes) {
        Date dNow = new Date();   //当前时间
        //获取当前时间段

        Date dBefore = new Date();
        Calendar calendar = Calendar.getInstance(); //得到日历
        calendar.setTime(dNow);//把当前时间赋给日历
        calendar.add(Calendar.DAY_OF_MONTH, -1);  //设置为前一天
        dBefore = calendar.getTime();   //得到前一天的时间
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); //设置时间格式
        SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); //设置时间格式
        String defaultStartDate = sdf.format(dBefore);    //格式化前一天
        String defaultEndDate = sdf.format(dNow); //格式化当前时间


        //设置班组信息
        if ("1".equals(classes.getIsAcross())) {

            //开始时间
            classes.setStartTime(defaultStartDate + " " + classes.getStartTime() + ":00");
            //结束时间
            classes.setEndTime(/*defaultEndDate + " " + classes.getEndTime()*/ sdf1.format(new Date()));
        } else {
            //开始时间
            classes.setStartTime(defaultEndDate + " " + classes.getStartTime() + ":00");
            //结束时间
            classes.setEndTime(/*defaultEndDate + " " + classes.getEndTime()*/ sdf1.format(new Date()));
        }
    }

    /**
     * 获取计划停机时间分钟
     */
    private List<DeviceAlarm> getPlannedStop(List<FactoryPlanHaltProductionDto> plannedStop, FactoryShiftDto classes) throws ParseException {
        double num = 0.0;
        Calendar cal = Calendar.getInstance();
        int year = cal.get(Calendar.YEAR);
        int month = cal.get(Calendar.MONTH) + 1;
        //获取按周休息的日期
        Set<FactoryPlanHaltProductionDto> list = new HashSet<>();
        //在班次的计划停机数据
        List<DeviceAlarm> list1 = new ArrayList<>();
        if (!CollectionUtils.isEmpty(plannedStop)) {
            //分组
            Map<String, List<FactoryPlanHaltProductionDto>> collect = plannedStop.stream().collect(Collectors.groupingBy(e -> e.getConfigType()));
            //获取按周停机时间
            List<FactoryPlanHaltProductionDto> factoryPlanHaltProductionDtos = collect.get("1");
            //获取按指定时间停机信息
            List<FactoryPlanHaltProductionDto> factoryPlanHaltProductionDtos1 = collect.get("0");
            if (!CollectionUtils.isEmpty(factoryPlanHaltProductionDtos1)) {
                list.addAll(factoryPlanHaltProductionDtos1);
            }
            if (!CollectionUtils.isEmpty(factoryPlanHaltProductionDtos)) {
                Map<String, String> monthFullDay = getMonthFullDay(year, month);
                for (FactoryPlanHaltProductionDto factoryPlanHaltProductionDto : factoryPlanHaltProductionDtos) {
                    list.addAll(getDayOff(monthFullDay, factoryPlanHaltProductionDto));
                }
            }

            //计算停机时间
            if (!CollectionUtils.isEmpty(list)) {
                DeviceAlarm deviceAlarm = new DeviceAlarm();
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                for (FactoryPlanHaltProductionDto factoryPlanHaltProductionDto : list) {
                    //班次在计划停机中
                    if (factoryPlanHaltProductionDto.getStartTime().compareTo(classes.getStartTime()) <= 0
                            && factoryPlanHaltProductionDto.getEndTime().compareTo(classes.getEndTime()) >= 0) {
                        deviceAlarm = new DeviceAlarm();
                        deviceAlarm.setStartTime(sdf.parse(classes.getStartTime()));
                        deviceAlarm.setEndTime(sdf.parse(classes.getEndTime()));
                        deviceAlarm.setTripTime(BigDecimal.valueOf(minuteDiff(classes.getStartTime(), classes.getEndTime())));
                        list1.add(deviceAlarm);
                    }
                    //班次结束时间在计划停机中
                    if (classes.getStartTime().compareTo(factoryPlanHaltProductionDto.getStartTime()) <= 0
                            && classes.getEndTime().compareTo(factoryPlanHaltProductionDto.getStartTime()) > 0
                            && classes.getEndTime().compareTo(factoryPlanHaltProductionDto.getEndTime()) <= 0) {
                        deviceAlarm = new DeviceAlarm();
                        deviceAlarm.setStartTime(sdf.parse(factoryPlanHaltProductionDto.getStartTime()));
                        deviceAlarm.setEndTime(sdf.parse(classes.getEndTime()));
                        deviceAlarm.setTripTime(BigDecimal.valueOf(minuteDiff(factoryPlanHaltProductionDto.getStartTime(), classes.getEndTime())));
                        list1.add(deviceAlarm);
                    }
                    //班次开始时间在计划停机中
                    if (classes.getStartTime().compareTo(factoryPlanHaltProductionDto.getStartTime()) >= 0
                            && classes.getStartTime().compareTo(factoryPlanHaltProductionDto.getEndTime()) < 0
                            && classes.getEndTime().compareTo(factoryPlanHaltProductionDto.getEndTime()) >= 0) {
                        deviceAlarm = new DeviceAlarm();
                        deviceAlarm.setStartTime(sdf.parse(classes.getStartTime()));
                        deviceAlarm.setEndTime(sdf.parse(factoryPlanHaltProductionDto.getEndTime()));
                        deviceAlarm.setTripTime(BigDecimal.valueOf(minuteDiff(classes.getStartTime(), factoryPlanHaltProductionDto.getEndTime())));
                        list1.add(deviceAlarm);
                    }
                    //计划时间在班次中的
                    if (classes.getStartTime().compareTo(factoryPlanHaltProductionDto.getStartTime()) < 0 && classes.getEndTime().compareTo(factoryPlanHaltProductionDto.getEndTime()) > 0) {
                        deviceAlarm = new DeviceAlarm();
                        deviceAlarm.setStartTime(sdf.parse(factoryPlanHaltProductionDto.getStartTime()));
                        deviceAlarm.setEndTime(sdf.parse(factoryPlanHaltProductionDto.getEndTime()));
                        deviceAlarm.setTripTime(BigDecimal.valueOf(minuteDiff(factoryPlanHaltProductionDto.getStartTime(), factoryPlanHaltProductionDto.getEndTime())));
                        list1.add(deviceAlarm);
                    }
                }
            }
        }
        return list1;
    }

    /**
     * java 获取 获取某年某月 所有日期（yyyy-mm-dd格式字符串）
     *
     * @param year
     * @param month
     * @return
     */
    public Map<String, String> getMonthFullDay(int year, int month) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); //设置时间格式
        Map<String, String> map = new HashMap<>(32);
        // 获得当前日期对象
        Calendar cal = Calendar.getInstance();
        cal.clear();// 清除信息
        cal.set(Calendar.YEAR, year);
        // 1月从0开始
        cal.set(Calendar.MONTH, month - 1);
        // 当月1号
        cal.set(Calendar.DAY_OF_MONTH, 1);
        int count = cal.getActualMaximum(Calendar.DAY_OF_MONTH);
        for (int j = 1; j <= count; j++) {
            String dayOfWeek = getDayOfWeek(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH) + 1, cal.get(Calendar.DAY_OF_MONTH));
            map.put(sdf.format(cal.getTime()), dayOfWeek);
            cal.add(Calendar.DAY_OF_MONTH, 1);
        }
        return map;
    }

    /**
     * 获取某年某月某日 是 星期几
     *
     * @param year
     * @param month
     * @param day
     * @return
     */
    public String getDayOfWeek(int year, int month, int day) {
        //本地化
        Locale.setDefault(Locale.CHINA);
        String[] dayStringOfWeek = {"7", "1", "2", "3", "4", "5", "6"};
        Calendar cal = Calendar.getInstance();
        cal.set(Calendar.YEAR, year);
        cal.set(Calendar.MONTH, month - 1);
        cal.set(Calendar.DAY_OF_MONTH, day);
        // Java中Calendar.DAY_OF_WEEK其实表示：一周中的第几天，所以他会受到第一天是 星期一 还是 星期日 的影响
        int d = cal.get(Calendar.DAY_OF_WEEK);
        return dayStringOfWeek[d - 1];
    }

    /**
     * @return
     */
    public List<FactoryPlanHaltProductionDto> getDayOff(Map<String, String> map, FactoryPlanHaltProductionDto factoryPlanHaltProductionDto) {
        List<FactoryPlanHaltProductionDto> list = new ArrayList<>();
        for (String s : map.keySet()) {
            if (map.get(s).equals(factoryPlanHaltProductionDto.getSpecifyTheWeek())) {
                FactoryPlanHaltProductionDto f = new FactoryPlanHaltProductionDto();
                f.setStartTime(s + " " + factoryPlanHaltProductionDto.getStartTime() + ":00");
                f.setEndTime(s + " " + factoryPlanHaltProductionDto.getEndTime() + ":00");
               /* //开始时间
                factoryPlanHaltProductionDto.setStartTime(s + " " + factoryPlanHaltProductionDto.getStartTime()+":00");
                //结束时间
                factoryPlanHaltProductionDto.setEndTime(s + " " + factoryPlanHaltProductionDto.getEndTime()+":00");*/
                list.add(f);
            }
        }
        return list;
    }

    //返回两个时间的分钟差
    public static double minuteDiff(String timeFrom, String timeTo) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        try {
            Date dFrom = sdf.parse(timeFrom);
            Date dTo = sdf.parse(timeTo);
            return minuteDiff(dFrom, dTo);
        } catch (Exception e) {
            throw new RuntimeException();
        }
    }

    //返回两个时间的分钟差
    public static double minuteDiff(Date timeFrom, Date timeTo) {
        double days = (double) (((double) timeTo.getTime() - timeFrom.getTime()) / (1000 * 60));
        return days;
    }

    /**
     * @param haltAll              总停机信息
     * @param equipmentMessageList 时间段停机数据
     * @param noStartingUp         停机后还没启动数据
     * @param timeQuantum          获取停机时间比开始时间早,但在这个时间段运行的停机信息
     * @param fullStop             获取停机时间大于这个时间段,运行时间也大于这个时间段的停机数据
     * @param classes              班次信息
     */
    public void getOutageInformation(List<DeviceAlarm> haltAll, List<DeviceAlarm> equipmentMessageList, List<DeviceAlarm> noStartingUp, List<DeviceAlarm> timeQuantum
            , List<DeviceAlarm> fullStop, FactoryShiftDto classes) throws ParseException {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        //时间段停机数据，直接插入
        if (!CollectionUtils.isEmpty(equipmentMessageList)) {
            haltAll.addAll(equipmentMessageList);
        }

        //停机后还没启动数据，计算停机时长插入
        if (!CollectionUtils.isEmpty(noStartingUp)) {
            for (DeviceAlarm deviceAlarm : noStartingUp) {
                if (sdf.format(deviceAlarm.getStartTime()).compareTo(classes.getStartTime()) <= 0) {
                    deviceAlarm.setTripTime(BigDecimal.valueOf(minuteDiff(classes.getStartTime(), classes.getEndTime())));
                    deviceAlarm.setStartTime(sdf.parse(classes.getStartTime()));
                    deviceAlarm.setEndTime(sdf.parse(classes.getEndTime()));
                } else if (sdf.format(deviceAlarm.getStartTime()).compareTo(classes.getEndTime()) < 0) {
                    deviceAlarm.setTripTime(BigDecimal.valueOf(minuteDiff(sdf.format(deviceAlarm.getStartTime()), classes.getEndTime())));
                    deviceAlarm.setEndTime(sdf.parse(classes.getEndTime()));
                }
                if (deviceAlarm.getStartTime() != null && StringUtils.hasText(sdf.format(deviceAlarm.getEndTime()))) {
                    haltAll.add(deviceAlarm);
                }
            }
        }
        //获取停机时间比开始时间早，但在这个时间段运行的停机信息
        if (!CollectionUtils.isEmpty(timeQuantum)) {
            for (DeviceAlarm deviceAlarm : timeQuantum) {
                deviceAlarm.setTripTime(BigDecimal.valueOf(minuteDiff(classes.getStartTime(), sdf.format(deviceAlarm.getEndTime()))));
                deviceAlarm.setStartTime(sdf.parse(classes.getStartTime()));
                haltAll.add(deviceAlarm);
            }
        }
        //获取停机时间大于这个时间段,运行时间也大于这个时间段的停机数据
        if (!CollectionUtils.isEmpty(fullStop)) {
            for (DeviceAlarm deviceAlarm : fullStop) {
                deviceAlarm.setTripTime(BigDecimal.valueOf(minuteDiff(classes.getStartTime(), classes.getEndTime())));
                deviceAlarm.setStartTime(sdf.parse(classes.getStartTime()));
                deviceAlarm.setEndTime(sdf.parse(classes.getEndTime()));
                haltAll.add(deviceAlarm);
            }
        }
        if (!CollectionUtils.isEmpty(haltAll)) {
            List<DeviceAlarm> ultimately = new ArrayList<>();
            getHalt(haltAll, ultimately, classes.getStartTime(), classes.getEndTime());
            haltAll.clear();
            haltAll.addAll(ultimately);
        }


    }

    /**
     * 去掉重复停机时间
     */
    /**
     * 去掉重复停机时间
     *
     * @param haltAll    总停机信息
     * @param ultimately 去掉重复时间信息
     * @param startTime  开始时间
     * @param endOfTime  结束时间
     */
    public void getHalt(List<DeviceAlarm> haltAll, List<DeviceAlarm> ultimately, String startTime, String endOfTime) throws ParseException {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        if (!CollectionUtils.isEmpty(haltAll)) {
            Collections.sort(haltAll, new Comparator<DeviceAlarm>() {
                @Override
                public int compare(DeviceAlarm o1, DeviceAlarm o2) {
                    return o2.getTripTime().compareTo(o1.getTripTime());
                }
            });
            //获取第一个参数
            DeviceAlarm deviceAlarm = haltAll.get(0);
            String haltTime1 = sdf.format(deviceAlarm.getStartTime());
            String nextBootTime1 = sdf.format(deviceAlarm.getEndTime());
            if (haltTime1.equals(startTime) && nextBootTime1.equals(endOfTime)) {
                //当停机时间与下次开机时间等于班次运行时间,表示当前时间段属于停机时间
                ultimately.clear();
                ultimately.add(deviceAlarm);
            } else {
                for (int i = 1; i < haltAll.size(); i++) {
                    String haltTime = sdf.format(haltAll.get(i).getStartTime());
                    String nextBootTime = sdf.format(haltAll.get(i).getEndTime());
                    //1.停机时间>=最大停机时间 下次开机时间=<最大下次开机时间
                    if ((haltTime.compareTo(haltTime1) > 0 || haltTime.compareTo(haltTime1) == 0) && (nextBootTime.compareTo(nextBootTime1) < 0 || nextBootTime.compareTo(nextBootTime1) == 0)) {
                        //删除该数据
                        haltAll.remove(i);
                        i--;
                    }
                    //2.停机时间<最大的停机时间 下次开机时间>最大的停机时间 下次开机时间<最大的下次开机时间
                    if (haltTime.compareTo(haltTime1) < 0 && nextBootTime.compareTo(haltTime1) > 0 && nextBootTime.compareTo(nextBootTime1) < 0) {
                        haltAll.get(0).setTripTime(BigDecimal.valueOf(minuteDiff(haltTime, sdf.format(haltAll.get(0).getEndTime()))));
                        haltAll.get(0).setStartTime(sdf.parse(haltTime));
                        haltAll.remove(i);
                        getHalt(haltAll, ultimately, startTime, endOfTime);
                        return;
                    }
                    //3.下次开机时间大于>最大的下次开机时间 停机时间<最大的下次开机时间
                    if (nextBootTime.compareTo(nextBootTime1) > 0 && haltTime.compareTo(nextBootTime1) < 0) {
                        //修改最大的那条数据
                        haltAll.get(0).setTripTime(BigDecimal.valueOf(minuteDiff(sdf.format(haltAll.get(0).getStartTime()), nextBootTime)));
                        haltAll.get(0).setEndTime(sdf.parse(nextBootTime));
                        haltAll.remove(i);
                        getHalt(haltAll, ultimately, startTime, endOfTime);
                        return;
                    }
                }
                haltAll.remove(0);
                ultimately.add(deviceAlarm);
                getHalt(haltAll, ultimately, startTime, endOfTime);
            }
        }
    }

    /**
     * 过滤处于计划停机的时间段的停机信息
     *
     * @param unplannedShutdown 非计划停机
     * @param plannedStop       计划停机
     */
    public void getOutageInformation(List<DeviceAlarm> unplannedShutdown, List<DeviceAlarm> plannedStop) {
        //当计划停机时间存在值时与非计划停机时间进行比较,去掉计划停机时间段的非计划停机时间
        if (!CollectionUtils.isEmpty(plannedStop) && !CollectionUtils.isEmpty(unplannedShutdown)) {
            for (DeviceAlarm wxData : plannedStop) {
                for (int i = 0; i < unplannedShutdown.size(); i++) {
                    //1.停机信息都处于计划停机时间,删除该信息
                    if (wxData.getStartTime().compareTo(unplannedShutdown.get(i).getStartTime()) <= 0
                            && wxData.getEndTime().compareTo(unplannedShutdown.get(i).getEndTime()) >= 0) {
                        unplannedShutdown.remove(i);
                        i--;
                    } else if (wxData.getStartTime().compareTo(unplannedShutdown.get(i).getStartTime()) >= 0
                            && wxData.getStartTime().compareTo(unplannedShutdown.get(i).getEndTime()) < 0
                            && wxData.getEndTime().compareTo(unplannedShutdown.get(i).getEndTime()) >= 0) {
                        //2.停机信息有部分处于计划停机时间
                        unplannedShutdown.get(i).setTripTime(BigDecimal.valueOf(minuteDiff(unplannedShutdown.get(i).getStartTime(), wxData.getStartTime())));
                        unplannedShutdown.get(i).setEndTime(wxData.getStartTime());
                    } else if (wxData.getStartTime().compareTo(unplannedShutdown.get(i).getStartTime()) <= 0
                            && wxData.getStartTime().compareTo(unplannedShutdown.get(i).getStartTime()) > 0) {
                        //3.停机信息有部分处于计划停机时间
                        unplannedShutdown.get(i).setTripTime(BigDecimal.valueOf(minuteDiff(wxData.getEndTime(), unplannedShutdown.get(i).getEndTime())));
                        unplannedShutdown.get(i).setStartTime(wxData.getEndTime());
                    } else if (wxData.getStartTime().compareTo(unplannedShutdown.get(i).getStartTime()) >= 0
                            && wxData.getEndTime().compareTo(unplannedShutdown.get(i).getEndTime()) <= 0) {
                        DeviceAlarm wx = new DeviceAlarm();
                        //4.停机信息中存在计划停机信息,将停机信息划分为两段
                        DeviceAlarm deviceAlarm = unplannedShutdown.get(i);
                        unplannedShutdown.remove(i);
                        i--;
                        wx.setStartTime(deviceAlarm.getStartTime());
                        wx.setEndTime(wxData.getStartTime());
                        wx.setTripTime(BigDecimal.valueOf(minuteDiff(deviceAlarm.getStartTime(), wxData.getStartTime())));
                        unplannedShutdown.add(wx);
                        wx = new DeviceAlarm();
                        wx.setStartTime(wxData.getEndTime());
                        wx.setEndTime(deviceAlarm.getEndTime());
                        wx.setTripTime(BigDecimal.valueOf(minuteDiff(wxData.getEndTime(), deviceAlarm.getEndTime())));
                        unplannedShutdown.add(wx);
                    }
                }
            }
        }
    }


}
